import java.util.ArrayList;
import java.io.*;

public class Bunga {

	private static final String VERSION = "0.2";
	private static final double TUNE_FACTOR = 2;
	private static final long LISTSIZE = 0;
	private static final int ASCII_OFFSET = 48;
	private static final int MAX_WORD_SIZE = 50;
	private static final String FILENAME = "dictionary.dic";
	private final char NULC = 0x00;
	private ArrayList<String> list1,list2,dictionary;
	private int wordSize = 0;
	private int firstLetterPos = 0; /*Usually position-- so we can use 0 indexed arrays easily*/
	
	private String word;

	//Constructor
	public Bunga(String[] args_in){
		if(!validate(args_in))return;
		//Load Dictionary into ram
		try{
			dictionary = loadDictionary(FILENAME);
		}catch(Exception e){
			System.out.print(e);
			e.printStackTrace();
			return;
		}
		//ok so now we have the first char and its position within the array
		//for the meantime I want to build a sub array based on this.
		//and so on, reducing possible matches each time
		//only two buffers should be required for this, but I doubt the garbage collector
		//will be able to keep up, so unfortunatly mem consumption will be high!
		
		list2 = new ArrayList<String>(0);

		//Normalise any numbers in our sequence to letters if possible
		word = args_in[2].toLowerCase();
		String normword = normalise(word);
		
		//Find all words with first correct charAt(firstLetterPos) == first known char
		ArrayList<String> results = returnWords(dictionary,normword);
		System.out.println(results);		
	}

	
	/*
	 * The Magic Bit, though it might be a little/lot slow, will have to have
	 * a look at a recursive option, but not right now
	 *
	 * TODO: Run against a profiler to see if the JVM is keeping up with de-allocation
	 * TODO: Find a more elegant solution
	 */
	private ArrayList<String> returnWords (ArrayList<String> dict, String partialWord){
		ArrayList<String> localList = new ArrayList<String>((int)dict.size()/4);
		
		for(String s : dict){
			if(s.length()>wordSize)continue;
			char[] wc = partialWord.toCharArray();			//Array of chars that must be set to NULC in sequence.
			for(int i=0;i<s.length();i++){				//Loop through chars in dict->string
				for(int j=0;j<wc.length;j++){			//Loop through known password chars
					if(s.charAt(i)==wc[j]){
						if(j==0){
							wc[0]=NULC;		//No Preceding known char to check
						}else{
							if(wc[j-1]==NULC){	//Check previous char found...
								wc[j]=NULC;
							}
						}
					}
				}
			}
			if(wc[wc.length-1]==NULC){
				localList.add(s);
			}
		}
		
		return localList;	
	}

	
	/*
	 * Pretty much redundant now!
	 */
	private boolean validate(String[] args_in){
	//ArraySize has already been validated by main
	//arguements :
	//-m <>
	//--max <>

		if(args_in[0].equals("-m") || args_in[0].equals("--max")){
			if(isInt(args_in[1])){
				this.wordSize = Integer.parseInt(args_in[1]);
			}else{
				this.wordSize = MAX_WORD_SIZE;
			}
		}//fall through to IF

		return true;
	}

	private boolean isInt(String in){
		try{
			int temp = Integer.parseInt(in);
			return true;
		}catch(Exception nan){
			return false;
		}
	}
    
	private String leetize(String in, String originaWord){
		char[] lt = new char[10];
		lt[0] = 'o';
		lt[1] = 'i'; //could also be l but I is more common statistically
		lt[2] = '2'; //no leet speak for 2?
		lt[3] = 'e';
		lt[4] = 'a';
		lt[5] = 's';
		lt[6] = 'b';
		lt[7] = 't';
		lt[8] = 'b';
		lt[9] = 'g';
		StringBuffer wordBuffer = new StringBuffer();
	
		for(int i = 0;i<in.length();i++){
			if(i < originaWord.length()){
				if(originaWord.charAt(i) > 47 && originaWord.charAt(i) < 59){
					wordBuffer.append(originaWord.charAt(i));
				}else{
					wordBuffer.append(in.charAt(i));
				}
			}else{
				wordBuffer.append(in.charAt(i));
			}
		}	
		String leetword = wordBuffer.toString();	
		return leetword;
	}
    
	private String normalise(String in){
		char[] lt = new char[10];
		lt[0] = 'o';
		lt[1] = 'i'; 
		lt[2] = '2'; //no leet speak for 2?
		lt[3] = 'e';
		lt[4] = 'a';
		lt[5] = 's';
		lt[6] = 'b';
		lt[7] = 't';
		lt[8] = 'b';
		lt[9] = 'g';
		StringBuffer wordBuffer = new StringBuffer();

		for(char c : in.toCharArray()){
			for(int i = 0; i<lt.length;i++){
				if(c==(char)i+ASCII_OFFSET) c = lt[i];
			}
			wordBuffer.append(c);
		}
		return(wordBuffer.toString());	
	}
   
	private ArrayList<String> loadDictionary(String dictName) throws BungaException{
		ArrayList<String> mem_dic = new ArrayList<String>(0);
		try{
			BufferedReader in = new BufferedReader(new FileReader(dictName));
			String tmp;
			while ((tmp = in.readLine()) != null){
				mem_dic.add(tmp.toLowerCase());
			}
			in.close();
		}catch (Exception e){
			throw new BungaException("Error Loading File");
		}    	
		return mem_dic;
	}
    
	private static void help(){
		System.out.print("\nBunga version " + VERSION + " pre alpha\n" +
			"java Bunga -r 5 -sl 2 una\n"+
			"--help\t\tthis message\n"+
			"-m / --max\tMax word length\n"
			);
	}
	
	public static void main(String[] args) {
		if(args.length != 3) {
			Bunga.help();
			return;
		}
		if(args[0].equals("--help") || args[0].equals("-h")){
			Bunga.help();
			return;
		}
		//anonymous invocation rocks!
		new Bunga(args);
	}
}
